package cn.qinhao.pethome.login.service.impl;

import cn.qinhao.pethome.basic.base.BaseConstants;
import cn.qinhao.pethome.basic.exception.BusinessException;
import cn.qinhao.pethome.basic.until.SendMsgUtil;
import cn.qinhao.pethome.basic.until.StrUtils;
import cn.qinhao.pethome.basic.until.VerifyCodeUtils;
import cn.qinhao.pethome.login.domain.PhoneCodeVo;
import cn.qinhao.pethome.login.service.ImgCodeGeneratedService;
import cn.qinhao.pethome.org.domain.User;
import cn.qinhao.pethome.org.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Service
public class ImgCodeGeneratedServiceImpl implements ImgCodeGeneratedService {
    //注入任意类型redis
    @Autowired
    private RedisTemplate redisTemplate;
    //注入用户的mapper
    @Autowired
    private UserMapper userMapper;
    //注入短信功能
    @Autowired
    private SendMsgUtil sendMsgUtil;

    @Override
    public String getImgCode(String uuid, String key) {
        //根据工具类生成 图形验证码 4位     toLowerCase()将字符串转化为小写去和用户比较，就是用户输入就不区分大小写就能输入
        String code = VerifyCodeUtils.generateVerifyCode(4).toLowerCase();
        //以uuid为key,生成的code为值存入redis，保证唯一性
        redisTemplate.opsForValue().set(uuid + key, code, 5, TimeUnit.MINUTES);
        //用Base64转化为浏览器可以直接显示的字符串
        try {
            String code1 = VerifyCodeUtils.VerifyCode(110, 42, code);
            //返回编译后可以直接在浏览器显示的code1
            return code1;
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("图片验证生成失败");
        }
    }

    //发送短信验证码
    @Override
    public void getPhoneCode(PhoneCodeVo phoneCodeVo) throws Exception {
        //1、校验参数
        if (phoneCodeVo.getMobile() == null || "".equals(phoneCodeVo.getMobile())) {
            throw new BusinessException("手机号不能为空");
        }
        if (phoneCodeVo.getImageCode() == null || "".equals(phoneCodeVo.getImageCode())) {
            throw new BusinessException("图片验证码不能为空");
        }//判断传过来的uuid不能为空
        if (phoneCodeVo.getImageCodeKey() == null || "".equals(phoneCodeVo.getImageCodeKey())) {
            throw new BusinessException("参数异常");
        }
        //2、校验图片验证码是否存在
        String imgCode = (String) redisTemplate.opsForValue().get(phoneCodeVo.getImageCodeKey() + BaseConstants.ImgCode.STATE_REGISTER);
        //2.1不存在则报过期
        if (imgCode == null) {
            throw new BusinessException("图片验证码已过期，请重新获取");
        }
        //2.2存在则判断输入的和redis中的是否一致
        if (!imgCode.equals(phoneCodeVo.getImageCode())) {
            throw new BusinessException("图片验证码输入错误");
        }
        //3、验证手机是否被注册
        //3.1查询用户是否存在，判断是否为空，不为空就已经被注册
        User user = userMapper.loadByPhone(phoneCodeVo.getMobile());
        if (user != null) {
            //3.1 存在 说明已经注册
            throw new BusinessException("手机号已被注册，请您去登录！！");
        }
        //3.2不存在——处理时间1分钟后才可以再次点击获取（通过手机号+业务键）——第一次进入没有设置到redis中，说明获取的时候就没有
        String keyCheck = phoneCodeVo.getMobile() + BaseConstants.ImgCode.STATE_REGISTER_CHECK;
        //3.4设置有效期为5分钟，但是3分钟只能发送同一个验证码，目的防止绕过前端到其他地方访问
        String key = phoneCodeVo.getMobile() + BaseConstants.ImgCode.STATE_REGISTER;
        //判断是否获取过一次
        Object o = redisTemplate.opsForValue().get(keyCheck);
        if (o == null) {
            //为空就没有获取到，就可以点击,把value提出来下面可以共用
            String Value = "";
            //通过key获取值，判断是否在3分钟之内
            Object phoneCode = redisTemplate.opsForValue().get(key);
            if (phoneCode == null) {//为空则不在3分钟内，创建验证码，再发送
                //获取随机的验证码(获取6位全数字的验证码)
                Value = StrUtils.getRandomString(6);
                //通过电话号码+业务键设置3分钟以内只能发送同一个验证码
                redisTemplate.opsForValue().set(key, Value, 3, TimeUnit.MINUTES);
                //同时设置1分钟才可以获取
                redisTemplate.opsForValue().set(keyCheck, "", 1, TimeUnit.MINUTES);
                //发送短信
                System.out.println("您的短信验证码为：" + Value);
            } else {//不等于空，还在3分钟类，则发送短信
                Value = phoneCode.toString();
                System.out.println("发送短信" + Value);
            }
            //真实发送短信
           // sendMsgUtil.sendPhone(phoneCodeVo.getMobile(), Value);
        } else {//不为空，则必须60秒后才能点击
            throw new BusinessException("您已经获取过一次，请在60秒之后再获取");
        }
    }
}
